package atlantik.ai;

import modelz.AbstractUpdateableCollectionListener;
import modelz.UpdateListener;
import atlantik.game.AbstractAtlantikListener;
import atlantik.game.Atlantik;
import atlantik.game.AtlantikListenerDispatcher;
import atlantik.game.AtlantikState;
import atlantik.game.Auction;
import atlantik.game.DetailAction;
import atlantik.game.Estate;
import atlantik.game.Game;
import atlantik.game.Player;
import atlantik.game.AtlantikClient;

public class SimpleAI extends AbstractAtlantikListener {

	protected final Atlantik client;

	protected final AtlantikListenerDispatcher dispatcher;

	protected final AtlantikState state;

	public SimpleAI(Atlantik client, AtlantikListenerDispatcher dispatcher) {
		this.client = client;
		this.dispatcher = dispatcher;
		this.state = client.getState();

		dispatcher.addListener(this);
		state.players().addListener(new PlayerListener());
		state.games().addListener(new GameListener());
		state.auctions().addListener(new AuctionListener());
		state.details().actions().addListener(new DetailActionListener());
	}

	private class PlayerListener extends
			AbstractUpdateableCollectionListener<Player> implements
			UpdateListener<Player> {
		public void added(Player player) {
			player.addListener(this);
			ai();
		}

		public void updated(Player player) {
			ai();
		}
	}

	private class GameListener extends
			AbstractUpdateableCollectionListener<Game> {
		public void added(Game game) {
			if (state.self().getGame() != null || !game.canBeJoined())
				return;

			if (game.getStatus() == Game.Status.NONE)
				client.join(game);
		}
	}

	private class AuctionListener extends
			AbstractUpdateableCollectionListener<Auction> implements
			UpdateListener<Auction> {
		public void added(Auction auction) {
			auction.addListener(this);
			auctionAi(auction);
		}

		public void updated(Auction auction) {
			auctionAi(auction);
		}
	}

	private class DetailActionListener extends
			AbstractUpdateableCollectionListener<DetailAction> {
		public void added(DetailAction action) {
			ai();
		}
	}

	void ai() {
		Player self = state.self();
		if (self.isMoving() || !self.hasTurn())
			return;

		houseAi();

		if (self.canRoll())
			client.rollDice();
		else {
			if (self.isJailed()) {
				if (self.canUseCard())
					client.jailCard();
				else if (self.getMoney() > 50)
					client.jailPay();
				else
					client.jailRoll();
			} else if (self.canBuyEstate() || self.canAuction()) {
				Estate estate = self.getLocation();
				if (estate != null)
					if (self.getMoney() > estate.getPrice()
							&& self.canBuyEstate())
						client.buyEstate();
					else if (self.canAuction())
						client.auctionEstate();
					else
						client.endTurn();
			} else{
				dispatcher.infoAdded("AI can't decide, it's your turn!");
				//added payFee() call to prevent AI from hanging game
				client.payFee();
			}
		}
	}

	private void houseAi() {
		Player self = state.self();
		boolean finished = false;
		while (!finished) {
			finished = true;
			for (Estate e : self.estates()) {
				if (e.canBuyHouses() && self.getMoney() >= e.getHousePrice()) {
					System.out.println("Can buy house for " + e.getName());
					client.estateHouseBuy(e);
				}
			}
		}
	}

	void auctionAi(Auction auction) {
		Player self = state.self();
		Auction.Bid highBid = auction.getHighBid();

		if (highBid != null && highBid.getBidder() == self)
			return;

		if (auction.getStatus() == Auction.Status.SOLD)
			return;

		int bid = 0;
		if (highBid != null)
			bid = highBid.getBid();
		bid++;
		int price = auction.getEstate().getPrice();
		int money = self.getMoney();
		if (bid < price && bid < money)
			client.auctionBid(auction, bid);
	}

}
